package com.ybl.store.backend.service.impl.deal;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ybl.store.backend.dao.entity.deal.DealProductDO;
import com.ybl.store.backend.dao.entity.deal.DealVoucherDO;
import com.ybl.store.backend.dao.entity.deal.LogDealProductPaymentDO;
import com.ybl.store.backend.dao.entity.item.VoucherDO;
import com.ybl.store.backend.dao.entity.deal.LogDealProductPaymentDO;
import com.ybl.store.backend.dao.entity.store.StoreDO;
import com.ybl.store.backend.dao.entity.user.ClerkDO;
import com.ybl.store.backend.dao.entity.user.CustomerDO;
import com.ybl.store.backend.dao.mapper.deal.DealProductMapper;
import com.ybl.store.backend.dao.mapper.deal.DealVoucherMapper;
import com.ybl.store.backend.dao.mapper.deal.LogDealProductNumberMapper;
import com.ybl.store.backend.dao.mapper.deal.LogDealProductPaymentMapper;
import com.ybl.store.backend.dao.mapper.item.VoucherMapper;
import com.ybl.store.backend.dao.mapper.store.StoreMapper;
import com.ybl.store.backend.dao.mapper.user.ClerkMapper;
import com.ybl.store.backend.dao.mapper.user.CustomerMapper;
import com.ybl.store.backend.dto.UserInfoDTO;
import com.ybl.store.backend.dto.req.deal.DealVoucherSaveReqDTO;
import com.ybl.store.backend.dto.req.deal.DealVoucherUpdateReqDTO;
import com.ybl.store.backend.dto.resp.deal.DealVoucherExportRespDTO;
import com.ybl.store.backend.dto.resp.deal.DealVoucherPageRespDTO;
import com.ybl.store.backend.service.deal.DealProductService;
import com.ybl.store.backend.service.deal.DealVoucherService;
import com.ybl.store.backend.service.deal.LogDealProductPaymentService;
import com.ybl.store.backend.service.impl.customer.CustomerVoucherService;
import com.ybl.store.common.constant.DealVoucherType;
import com.ybl.store.common.constant.UserPermission;
import com.ybl.store.common.constant.VoucherUsageStatus;
import com.ybl.store.common.context.UserContext;
import com.ybl.store.common.convention.errorcode.BaseErrorCode;
import com.ybl.store.common.convention.exception.ClientException;
import com.ybl.store.common.entity.ListRespDTO;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
@RequiredArgsConstructor
@Transactional
public class DealVoucherServiceImpl extends ServiceImpl<DealVoucherMapper, DealVoucherDO> implements DealVoucherService {

    private final StoreMapper storeMapper;

    private final ClerkMapper clerkMapper;

    private final CustomerMapper customerMapper;

    private final VoucherMapper voucherMapper;

    private final DealVoucherMapper dealVoucherMapper;

//    private final VoucherServiceImpl voucherService;

    private final CustomerVoucherService customerVoucherService;

//    private final DealProductMapper dealProductMapper;

    private final LogDealProductPaymentMapper logDealProductPaymentMapper;

//    private final DealProductService dealProductService;

    @Override
    public void saveDealVoucher(DealVoucherSaveReqDTO requestParam) {
        checkIds(BeanUtil.toBean(requestParam, DealIds.class));

        // 更新卡券 & 更新顾客
        if (Objects.equals(requestParam.getType(), DealVoucherType.distributed)) {
//            voucherService.setDistributionBitmap(requestParam.getSerial(), '1');
            customerVoucherService.set(requestParam.getCustomerId(), requestParam.getVoucherId(), requestParam.getSerial(), VoucherUsageStatus.unused);
        }
        else if (Objects.equals(requestParam.getType(), DealVoucherType.used)) {
//            voucherService.setUsageBitmap(requestParam.getSerial(), '1');
            customerVoucherService.set(requestParam.getCustomerId(), requestParam.getVoucherId(), requestParam.getSerial(), VoucherUsageStatus.used);
        }
        checkSameSerial(requestParam.getSerial());
        // 更新订单
        int result = baseMapper.insert(BeanUtil.toBean(requestParam, DealVoucherDO.class));
        if (result < 1) {
            throw new ClientException(BaseErrorCode.DEAL_VOUCHER_SAVE_ERROR);
        }
    }

    @Override
    public void deleteDealVoucher(Long id) {
        DealVoucherDO dealVoucherDO = baseMapper.selectById(id);
        if (dealVoucherDO == null) {
            throw new ClientException(BaseErrorCode.DEAL_VOUCHER_NULL_ERROR);
        }

        // 更新卡券
//        if (Objects.equals(dealVoucherDO.getType(), DealVoucherType.distributed)) {
//            voucherService.setDistributionBitmap(dealVoucherDO.getSerial(), '0');
//            voucherService.setUsageBitmap(dealVoucherDO.getSerial(), '0');
//        }
//        else if (Objects.equals(dealVoucherDO.getType(), DealVoucherType.used)) {
//            voucherService.setUsageBitmap(dealVoucherDO.getSerial(), '0');
//        }

        // 更新顾客
        customerVoucherService.del(dealVoucherDO.getCustomerId(), dealVoucherDO.getVoucherId(), dealVoucherDO.getSerial());

        // 更新订单
        int result = baseMapper.deleteById(id);
        if (result < 1) {
            throw new ClientException(BaseErrorCode.DEAL_VOUCHER_DELETE_ERROR);
        }
    }

    @Override
    public void updateDealVoucher(DealVoucherUpdateReqDTO requestParam) {
//        DealIds idd = BeanUtil.toBean(requestParam, DealIds.class);
//        checkIds(idd);
        checkIds(BeanUtil.toBean(requestParam, DealIds.class));
        DealVoucherDO dealVoucherDO = baseMapper.selectById(requestParam.getId());
        if (dealVoucherDO == null) {
            throw new ClientException(BaseErrorCode.DEAL_VOUCHER_NULL_ERROR);
        }

//        deleteDealVoucher(dealVoucherDO.getId());
//
//        saveDealVoucher(BeanUtil.toBean(requestParam, DealVoucherSaveReqDTO.class));
        checkUpdateSerial(requestParam.getSerial(),requestParam.getId());
        // 更新订单
        int result = baseMapper.updateById(BeanUtil.toBean(requestParam, DealVoucherDO.class));
        if (result < 1) {
            throw new ClientException(BaseErrorCode.DEAL_VOUCHER_UPDATE_ERROR);
        }
    }

    @Override
    public ListRespDTO<DealVoucherPageRespDTO> pageDealVoucher(Integer pn, Integer ps, Long storeId, Long clerkId, Long customerId, Long voucherId, String startTime, String endTime, Integer type) {
        UserInfoDTO userInfoDTO = UserContext.get();
        if (!Objects.equals(userInfoDTO.getPermission(), UserPermission.ADMIN)) {
            storeId = userInfoDTO.getStoreId();
            clerkId = userInfoDTO.getId();
        }
        boolean timeCondition = Objects.nonNull(startTime) && Objects.nonNull(endTime);

        Page<DealVoucherPageRespDTO> page = new Page<>(pn, ps);
        QueryWrapper<DealVoucherDO> queryWrapper = Wrappers.query(DealVoucherDO.class)
                .eq(Objects.nonNull(storeId), "deal.store_id", storeId)
                .eq(Objects.nonNull(clerkId), "deal.clerk_id", clerkId)
                .eq(Objects.nonNull(customerId), "deal.customer_id", customerId)
                .eq(Objects.nonNull(voucherId), "deal.voucher_id", voucherId)
                .between(timeCondition, "deal.deal_time", startTime, endTime)
                .eq(Objects.nonNull(type), "deal.type", type)
                .eq("deal.del_flag", 0)
                .orderByDesc("deal.deal_time");
        List<DealVoucherPageRespDTO> dealVoucherPageRespDTOList = baseMapper.pageDealVoucher(page, queryWrapper);

        queryWrapper = Wrappers.query(DealVoucherDO.class)
                .eq(Objects.nonNull(storeId), "store_id", storeId)
                .eq(Objects.nonNull(clerkId), "clerk_id", clerkId)
                .eq(Objects.nonNull(customerId), "customer_id", customerId)
                .eq(Objects.nonNull(voucherId), "voucher_id", voucherId)
                .between(timeCondition, "deal_time", startTime, endTime)
                .eq(Objects.nonNull(type), "type", type);
        Long total = baseMapper.selectCount(queryWrapper);

        return ListRespDTO.<DealVoucherPageRespDTO>builder()
                .total(total)
                .items(dealVoucherPageRespDTOList
                        .stream()
                        .map(each -> BeanUtil.toBean(each, DealVoucherPageRespDTO.class))
                        .toList())
                .build();
    }

    @Override
    public List<DealVoucherExportRespDTO> export() {
        return baseMapper.export();
    }

    @Data
    static class DealIds {
        private Long storeId;
        private Long clerkId;
        private Long customerId;
        private Long voucherId;
    }
    /**
     * 检查 编号 是否存在
     *
     * @param serial 待检查的 编号
     */
    private void checkSameSerial(String serial) {
        Map<String,Object> map = new HashMap<>();
        map.put("serial",serial);
        List<DealVoucherDO>  dealVoucherDO = dealVoucherMapper.selectByMap(map);
        if(!dealVoucherDO.isEmpty()){
            throw new ClientException(BaseErrorCode.VOUCHER_DISTRIBUTION_ERROR);
        }

    }
    /**
     * 检查 编号 是否存在
     *
     * @param serial 待检查的 编号
     * @param id 卡券订单编号
     */
    private void checkUpdateSerial(String serial,Long id) {
        DealVoucherDO dealVoucherDO = dealVoucherMapper.selectById(id);
        Map<String,Object> map = new HashMap<>();
        if(dealVoucherDO != null){
            if(!Objects.equals(serial,dealVoucherDO.getSerial())){
                map.put("serial",serial);
                List<DealVoucherDO>  dealVoucher = dealVoucherMapper.selectByMap(map);
                if(!dealVoucher.isEmpty()){
                    throw new ClientException(BaseErrorCode.VOUCHER_DISTRIBUTION_ERROR);
                }
            };
        }
    }
    /**
     * 检查 ids 是否存在且合法
     *
     * @param dealIds 待检查的 ids
     */
    private void checkIds(DealIds dealIds) {
        UserInfoDTO userInfoDTO = UserContext.get();
        StoreDO storeDO = storeMapper.selectById(dealIds.getStoreId());
        ClerkDO clerkDO = clerkMapper.selectById(dealIds.getClerkId());
        CustomerDO customerDO = customerMapper.selectById(dealIds.getCustomerId());
        VoucherDO voucherDO = voucherMapper.selectById(dealIds.getVoucherId());

        // 检查 ids 是否存在
        if (storeDO == null) {
            throw new ClientException(BaseErrorCode.STORE_NULL_ERROR);
        }
        if (clerkDO == null) {
            throw new ClientException(BaseErrorCode.CLERK_NULL_ERROR);
        }
        if (customerDO == null) {
            throw new ClientException(BaseErrorCode.CUSTOMER_NULL_ERROR);
        }
        if (voucherDO == null) {
            throw new ClientException(BaseErrorCode.VOUCHER_NULL_ERROR);
        }

        // 当前登录用户是否有权限
        if (!Objects.equals(userInfoDTO.getPermission(), UserPermission.ADMIN)) {
            if (!Objects.equals(clerkDO.getId(), userInfoDTO.getId())) {
                throw new ClientException(BaseErrorCode.CLIENT_UNAUTHORIZED_ERROR);
            }
        }

        // 检查 ids 是否合法
        if (!Objects.equals(clerkDO.getStoreId(), storeDO.getId()) ||
                !Objects.equals(customerDO.getClerkId(), clerkDO.getId())
        ) {
            throw new ClientException(BaseErrorCode.CLIENT_UNAUTHORIZED_ERROR);
        }
    }
    /**
     * 检查 卡券 是否存在且未被使用
     *
     * @param serial 待检查的卡券编号
     */
    public void checkSerial(String serial,Long dealProductId) {
        Map<String,Object> map = new HashMap<>();
        map.put("serial",serial);
        List<DealVoucherDO>  dealVoucherDO = dealVoucherMapper.selectByMap(map);
//        DealProductDO  dealProductDO =dealProductMapper.selectById(dealProductId);
        if(dealVoucherDO.isEmpty()){
            throw new ClientException(BaseErrorCode.DEAL_VOUCHER_NULL_ERROR);
        }
//        if(!Objects.equals(dealVoucherDO.getCustomerId(), dealProductDO.getCustomerId())){
//            throw new ClientException(BaseErrorCode.CLIENT_UNAUTHORIZED_ERROR);
//        }
        if(dealVoucherDO.get(0).getType()!=0){
            throw new ClientException(BaseErrorCode.VOUCHER_USAGE_ERROR);
        }
    }
    public void updateType(String serial,Long dealProductId){
        Map<String,Object> map = new HashMap<>();
        map.put("serial",serial);
        List<DealVoucherDO>  dealVoucherDO = dealVoucherMapper.selectByMap(map);
        if(dealVoucherDO.isEmpty()){
            throw new ClientException(BaseErrorCode.DEAL_VOUCHER_NULL_ERROR);
        }
        DealVoucherDO dealVoucherDO1 = BeanUtil.toBean(dealVoucherDO.get(0),DealVoucherDO.class);
        dealVoucherDO1.setType(1);
        dealVoucherDO1.setDealProductId(dealProductId);
        int result = baseMapper.updateById(dealVoucherDO1);
        if (result < 1) {
            throw new ClientException(BaseErrorCode.DEAL_VOUCHER_UPDATE_ERROR);
        }
    }
    public void exchangeVoucher(Long dealPaymentId){
        LogDealProductPaymentDO logDealProductPaymentDO = logDealProductPaymentMapper.selectById(dealPaymentId);
        Map<String,Object> map = new HashMap<>();
        map.put("serial",logDealProductPaymentDO.getDealVocherSerial());
        List<DealVoucherDO>  dealVoucherDO = dealVoucherMapper.selectByMap(map);
        if(dealVoucherDO.isEmpty()){
            throw new ClientException(BaseErrorCode.DEAL_PRODUCT_NULL_ERROR);
        }
        DealVoucherDO dealVoucherDO1 = BeanUtil.toBean(dealVoucherDO.get(0),DealVoucherDO.class);
        dealVoucherDO1.setType(0);
        dealVoucherDO1.setDealProductId(null);
        int result = baseMapper.updateById(dealVoucherDO1);
        if (result < 1) {
            throw new ClientException(BaseErrorCode.DEAL_VOUCHER_UPDATE_ERROR);
        }

    }

}
